package com.fanyue.modules.face.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.arcsoft.face.*;
import com.arcsoft.face.enums.*;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.fanyue.core.base.BaseServiceImpl;
import com.fanyue.core.cache.CoolCache;
import com.fanyue.core.constant.CommonConstant;
import com.fanyue.core.exception.CoolException;
import com.fanyue.core.request.R;
import com.fanyue.modules.face.config.ArcsoftProperties;
import com.fanyue.modules.face.config.FaceEngineCenter;
import com.fanyue.modules.face.entity.AppUser;
import com.fanyue.modules.face.entity.AppUserFace;
import com.fanyue.modules.face.mapper.AppUserFaceMapper;
import com.fanyue.modules.face.mapper.AppUserMapper;
import com.fanyue.modules.face.service.FaceEngineService;
import com.fanyue.modules.face.service.IFaceService;
import com.fanyue.modules.face.vo.FaceSimilarVO;
import com.fanyue.modules.face.vo.FaceVO;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
@EnableConfigurationProperties(ArcsoftProperties.class)
public class FaceServiceImpl extends BaseServiceImpl<AppUserFaceMapper, AppUserFace> implements IFaceService {

    private final CoolCache coolCache;
    private final ArcsoftProperties arcsoftProperties;
    // private final FaceEngine faceEngine;
    private final AppUserFaceMapper baseMapper;
    private final AppUserMapper appUserMapper;

    private static Map<String, FaceEngine> faceEngineCenter = new HashMap<>();

    @Override
    public R userInfo(Long userId) {
        AppUser appUser = appUserMapper.selectOneById(userId);
        AppUserFace appUserFace = mapper.selectOneByQuery(new QueryWrapper().eq("user_id", userId));
        return R.ok(appUserFace);
    }

    @Override
    public R featureList() {
        //获取人脸解析引擎
        FaceEngine faceEngine = getFaceEngine();
        VersionInfo versionInfo = faceEngine.getVersion();
        String version = versionInfo.getVersion();
        log.info("（人脸查询）FaceEngine版本: {}", version);
        FaceSearchCount faceSearchCount = new FaceSearchCount();
        int faceCount = faceEngine.getFaceCount(faceSearchCount);
        return R.ok(faceSearchCount.getCount());
    }

    @Override
    public R extractFeature(String type, Long userId, MultipartFile file, String facePath) {
        //查询用户信息
        AppUser appUser = appUserMapper.selectOneById(userId);
        if (ObjectUtil.isEmpty(appUser)) {
            return R.error("未查询到用户信息，请确认");
        }

        // 构建文件目录
        String yyyyMM = DateUtil.format(new Date(), "yyyyMM");
        String dd = DateUtil.format(new Date(), "dd");
        String faceFilePath = arcsoftProperties.getDirectory() + "/face/image/" + File.separator + yyyyMM + File.separator + dd + File.separator + userId + ".jpg";
        boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
        if (isWindows) {
            faceFilePath = "D:\\Data\\Temp\\face\\" + userId + ".jpg";
        }
        if (FileUtil.exist(faceFilePath)) {
            FileUtil.del(faceFilePath);
        }
        File faceFile = FileUtil.newFile(faceFilePath);

        switch (type) {
            case "multipartFile":
                try {
                    FileUtil.writeFromStream(file.getInputStream(), faceFile, true);
                } catch (IOException e) {
                    return R.error("解析人脸数据失败，请重新上传");
                }
                break;
            case "filePath":
                try {
                    FileUtil.copy(facePath, faceFilePath, true);
                } catch (Exception e) {
                    return R.error("解析人脸数据失败，请重新上传");
                }
                break;
        }
        //构建图片地址，返回结果为下载文件大小
        //String suffix = FileUtil.getSuffix(originalFilename);

        //获取人脸解析引擎
        FaceEngine faceEngine = getFaceEngine();
        VersionInfo versionInfo = faceEngine.getVersion();
        String version = versionInfo.getVersion();
        log.info("（人脸注册）FaceEngine版本: {}", version);
        //人脸检测
        ImageInfo imageInfo = ImageFactory.getRGBData(faceFile);
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
        int detectFacesCode = faceEngine.detectFaces(imageInfo, faceInfoList);
        log.info("人脸检测状态:{}" , detectFacesCode == 0 ? "正常" : "异常");
        if (detectFacesCode != 0) {
            delFaceFile(faceFilePath);
            return R.error("系统人脸检测失败，请重新拍摄");
        }

        // 判断画面没有人脸，返回提示
        if (faceInfoList.size() == 0) {
            delFaceFile(faceFilePath);
            return R.error("系统未检测到人脸数据，请重新拍摄");
        }
        // 判断画面大于一张人脸，返回提示
        if (faceInfoList.size() > 1) {
            delFaceFile(faceFilePath);
            return R.error("系统检测到当前图像包含多个人脸数据，请重新拍摄");
        }

        //图片质量检测
        ImageQuality imageQuality = new ImageQuality();
        int qualityCode = faceEngine.imageQualityDetect(imageInfo, faceInfoList.get(0), 0, imageQuality);
        log.info("图像质量检测code: {}", qualityCode);
        log.info("图像质量分数: {}", imageQuality.getFaceQuality());
        if (qualityCode != 0) {
            delFaceFile(faceFilePath);
            return R.error("系统检测图像数据异常，请重新拍摄");
        }

        //人脸属性检测
        FunctionConfiguration configuration = new FunctionConfiguration();
        configuration.setSupportAge(true);
        configuration.setSupportGender(true);
        configuration.setSupportLiveness(true);
        configuration.setSupportMaskDetect(true);
        int processCode = faceEngine.process(imageInfo, faceInfoList, configuration);
        log.info("图像处理Code: {}", processCode);

        //获取人脸三维角度信息
        //List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
        Face3DAngle face3DAngle = faceInfoList.get(0).getFace3DAngle();
        log.info("face3D检测偏航角：{}", face3DAngle.getYaw());
        log.info("face3D检测横滚角：{}", face3DAngle.getRoll());
        log.info("face3D检测俯仰角：{}", face3DAngle.getPitch());
		/*if (face3DAngleList.get(0).getStatus() != 0) {
			return R.error("系统检测到当前图像人脸角度异常，请重新拍摄");
		}*/
        float yaw = face3DAngle.getYaw();
        float pitch = face3DAngle.getPitch();
        if ((-15f > yaw || yaw > 15f) || (-15f > pitch || pitch > 15f)) {
            delFaceFile(faceFilePath);
            return R.error("系统检测到当前图像人脸角度异常，请重新拍摄");
        }

        Integer livenessSign = arcsoftProperties.getLivenessSign();
        livenessSign = ObjectUtil.isEmpty(livenessSign) ? 0 : livenessSign;
        if (livenessSign == 1) {
            //活体检测
            List<LivenessInfo> livenessInfoList = new ArrayList<>();
            int livenessCode = faceEngine.getLiveness(livenessInfoList);
            log.info("活体检测code: {}", livenessCode);
            if (livenessCode != 0) {
                return R.error("活体检测失败，请重新进行识别");
            }
            log.info("活体：{}", livenessInfoList.get(0).getLiveness());

            /**
             * 0：非真人； 1：真人；-1：不确定； -2：传入人脸数 > 1；-3: 人脸过小；-4: 角度过大；
             * -5: 人脸超出边界；-6：深度图错误；-7：红外图过亮；-8：红外图过暗；-100：人脸质量错误
            */
            if (CollUtil.isNotEmpty(livenessInfoList)) {
                int liveness = livenessInfoList.get(0).getLiveness();
                switch (liveness) {
                    //case 0:
                        //return R.error("系统检测到当前非真人，请进行真人识别");
                    case -1:
                        return R.error("系统检测到当前不确定非真人，请重新进行识别");
                    case -2:
                        return R.error("系统检测到当前传入人脸数大于1，请重新进行识别");
                    case -5:
                        return R.error("系统检测到当前人脸超出边界，请重新进行识别");
                    case -100:
                        return R.error("系统检测到当前人脸质量过低，请重新进行识别");
                }
            } else {
                return R.error("活体检测失败，请重新进行识别");
            }
        }

        //口罩检测
        List<MaskInfo> maskInfoList = new ArrayList<MaskInfo>();
        int maskCode = faceEngine.getMask(maskInfoList);
        log.info("口罩检测Code: {}", maskCode);
        if (maskCode != 0) {
            delFaceFile(faceFilePath);
            return R.error("系统检测口罩失败，请重新拍摄");
        }
        int maskSign = maskInfoList.get(0).getMask();
        log.info("检测口罩: {}", maskSign);


        // faceEngine.processIr(imageInfo, faceInfoList, configuration);

        //人像特征提取
        FaceFeature faceFeature = new FaceFeature();
        int featureCode = faceEngine.extractFaceFeature(imageInfo, faceInfoList.get(0), ExtractType.REGISTER, maskSign, faceFeature);
        log.info("特征值状态:{}" , featureCode == 0 ? "正常" : "异常");

        //人脸特征解析成功之后进行
        if (featureCode == 0) {
            log.info("抽取Feature长度：{}", faceFeature.getFeatureData().length);
            // String featureData = Convert.toStr(faceFeature.getFeatureData());

            String featureData = Base64.encode(faceFeature.getFeatureData());

            //对解析的数据进行数据比对
            FaceVO faceVO = new FaceVO();
            faceVO.setFeatureData(featureData);
            if (StrUtil.isNotEmpty(facePath)) {
                faceVO.setType("extract4System");
            }
            R compareResult = compareFeature(faceVO, 0);
            int code = Integer.parseInt(compareResult.get("code").toString());
            Object data = compareResult.get("data");
            if (code == 200) {
                ConverterRegistry registry = ConverterRegistry.getInstance();
                Map convert = registry.convert(Map.class, data);
                AppUser appUserInfo = registry.convert(AppUser.class, convert.get("userInfo"));
                if (!appUserInfo.getId().equals(userId)) {
                    return R.error("检测到系统已存在当前人脸数据，匹配用户：" + appUserInfo.getName() + "，请确认后重新上传！");
                }
            }

            //更新人脸文件
            Img.from(FileUtil.file(faceFilePath))
                    //压缩比率
                    .setQuality(0.6)
                    //.rotate(270)
                    .write(FileUtil.file(faceFilePath));

            //判断人脸库是否有当前用户数据，有则更新
            AppUserFace dbUserFace = mapper.selectOneByQuery(new QueryWrapper().eq("user_id", userId));

            if (ObjectUtil.isEmpty(dbUserFace)) {

                //寻找最后一条数据
                Integer searchId = baseMapper.selectLastSearchId();
                searchId = ObjectUtil.isEmpty(searchId) ? 1 : searchId + 1;

                // 存入人脸数据库
                AppUserFace userFace = new AppUserFace();
                userFace.setUserId(userId);
                userFace.setSearchId(searchId);
                userFace.setFaceFilePath(faceFilePath);
                userFace.setFeature(featureData);
                userFace.setNote(userId + "-人脸数据");
                userFace.setIsSync(0);
                this.save(userFace);

                appUser.setFaceId(userFace.getId());

                //注册人脸信息
                FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
                faceFeatureInfo.setSearchId(searchId);
                faceFeatureInfo.setFaceTag(userId + "用户人脸数据, 对应SearchId为：" + searchId);
                faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());
                int registerCode = faceEngine.registerFaceFeature(faceFeatureInfo);
                if (registerCode != 0) {
                    delFaceFile(faceFilePath);
                    return R.error("系统注册人脸信息失败，请重新操作");
                }
                log.info("人脸信息注册状态:{}", registerCode);

                FaceSearchCount faceSearchCount = new FaceSearchCount();
                int faceCount = faceEngine.getFaceCount(faceSearchCount);
                log.info("当前引擎缓存人脸数量：{}", faceSearchCount.getCount());

            } else {
                dbUserFace.setIsSync(0);
                dbUserFace.setFeature(featureData);
                dbUserFace.setFaceFilePath(faceFilePath);
                this.updateById(dbUserFace);

                appUser.setFaceId(dbUserFace.getId());

                //更新人脸信息
                FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();

                int faceFeatureInfoCode = faceEngine.getFaceFeature(dbUserFace.getSearchId(), faceFeatureInfo);
                if (faceFeatureInfoCode == 0) {
                    //FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
                    //faceFeatureInfo.setSearchId(dbUserFace.getSearchId());
                    //faceFeatureInfo.setFaceTag(userId + "用户人脸数据, 对应SearchId为：" + dbUserFace.getSearchId());
                    faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());
                    int updateCode = faceEngine.updateFaceFeature(faceFeatureInfo);
                    log.info("更新返回：{}", updateCode);
                } else {
                    //重新注册人脸信息
                    faceFeatureInfo.setSearchId(dbUserFace.getSearchId());
                    faceFeatureInfo.setFaceTag(userId + "用户人脸数据, 对应SearchId为：" + dbUserFace.getSearchId());
                    faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());
                    int registerCode = faceEngine.registerFaceFeature(faceFeatureInfo);
                    //faceEngine.removeFaceFeature()
                    if (registerCode != 0) {
                        delFaceFile(faceFilePath);
                        return R.error("系统注册人脸信息失败，请重新操作");
                    }
                    FaceSearchCount faceSearchCount = new FaceSearchCount();
                    int faceCount = faceEngine.getFaceCount(faceSearchCount);
                    log.info("重新注册-引擎缓存人脸数量：{}", faceCount);
                }
				/*if (updateCode != 0) {
					return R.error("系统更新人脸信息失败，请重新操作");
				}*/
            }
            //更新用户人脸数据
            appUserMapper.update(appUser);

            //将人脸数据存入redis中
            String cacheKey = CommonConstant.USER_FACE_ENGINE + arcsoftProperties.getAppName() + ":" + userId;
            // String cacheKey = CommonConstant.USER_FACE_ENGINE + ":" + userId;
            coolCache.set(cacheKey, featureData);
        } else {
            delFaceFile(faceFilePath);
            return R.error("人脸解析失败，请重新拍摄");
        }
        return R.ok("人脸数据解析成功");
    }

    @Override
    public R compareFeature(FaceVO faceVO, Integer type) {
        Map<String, Object> result = new HashMap<>();
        Long userId = null;
        Boolean useCache = true;

        // log.info("接收的FeatureData：{}", faceVO.getFeatureData());
        byte[] featureBytes = Base64.decode(faceVO.getFeatureData());
        log.info("比对Feature长度：{}", featureBytes.length);

        FaceEngine faceEngine = getFaceEngine();
        VersionInfo versionInfo = faceEngine.getVersion();
        String version = versionInfo.getVersion();
        log.info("（人脸对比）FaceEngine版本: {}", version);

        FaceFeature faceFeature = new FaceFeature();
        faceFeature.setFeatureData(featureBytes);

        // 获取人脸匹配分数,如果type=0（检测重复性）
        Float maxScore = arcsoftProperties.getMaxScore();
        if (type == 1) {
            maxScore = ObjectUtil.isEmpty(maxScore) ? 0.8f : maxScore;
        } else {
            maxScore = 0.98f;
        }

        log.info("本次匹配的最大分数值为：{}", maxScore);
        FaceSimilarVO faceSimilarData = new FaceSimilarVO();
        faceSimilarData.setMaxSimilarScore(0f);
        result.put("faceSimilar", faceSimilarData);

        //搜索最相似人脸
        SearchResult searchResult = new SearchResult();
        int searchCode = faceEngine.searchFaceFeature(faceFeature, CompareModel.LIFE_PHOTO, searchResult);
        log.info("引擎比对人脸比对Code：{}", searchCode);
        if (searchCode == 0) {
            log.info("------------使用引擎进行比对中...");
            float maxSimilar = searchResult.getMaxSimilar();
            int searchId = searchResult.getFaceFeatureInfo().getSearchId();
            log.info("***引擎比对最匹配人脸Id: {}", searchResult.getFaceFeatureInfo().getSearchId());
            log.info("***引擎比对最匹配人脸分数: {}", searchResult.getMaxSimilar());
            if (maxSimilar >= maxScore) {
                //根据SearchId查询用户id
                userId = baseMapper.selectUserIdBySearchId(searchId);
                AppUser appUserInfo = appUserMapper.selectOneById(userId);
                if (ObjectUtil.isNotEmpty(appUserInfo)) {
                    useCache = false;
                    faceSimilarData.setUserId(userId);
                    faceSimilarData.setMaxSimilarScore(maxSimilar);
                }
            }
        }

        // 设置匹配的用户id集合
        List<FaceVO> userFaceList = new ArrayList<>();

        if (useCache) {
            log.info("------------使用缓存数据进行比对中...");
            //byte[] targetFeatureArray = Convert.toPrimitiveByteArray(faceVO.getFeatureData());

            //获取人脸库数据
            //byte[] faceFeatureData = new byte[]{0, -128, -6, 68, 0, 0, -96, 65, 37, 75, 11, 60, 107, 24, -84, -70, -30, 88, -78, -67, 69, 12, -106, 58, 93, 121, -126, 61, -50, 3, 45, -68, -17, 72, -51, -67, 78, -124, -66, -68, -53, 12, -83, -67, -51, 5, 113, -68, 67, 87, 92, 61, -55, -44, -52, -68, 112, -28, -120, -67, -41, -38, 69, -67, -123, 80, -59, 60, -54, -114, -120, 61, -113, 33, 87, -68, 54, -40, -33, -67, -24, 124, -10, 61, -116, 26, -116, 61, -34, 121, 116, -67, -43, -113, -66, 60, 93, 80, -73, -68, -103, 2, 35, -68, -94, -63, 26, 62, 27, -27, -127, 61, 64, 62, -112, -68, -105, 58, 68, 61, -9, 126, 109, -67, 62, -23, 16, 62, -11, 116, -79, 61, 32, 80, -41, 61, 87, 126, 124, -67, -90, -122, -59, 60, -107, -38, 64, -68, 37, 111, -43, 60, -64, 94, -92, -67, 127, -109, -48, 59, -128, -105, 41, -67, -118, 120, 16, 61, -33, -126, -113, -67, -38, 48, -117, 61, 75, 67, -77, -68, -49, 47, 115, 61, 57, 67, 84, -68, -7, 87, -26, -67, 67, 53, -5, -68, 114, -44, -72, 60, 8, -30, 125, -67, 113, 16, 88, -67, 70, -85, 86, 61, -94, 12, 33, -67, 27, 114, -78, 61, 67, -89, -25, -67, 43, 107, 4, -69, -24, -122, -43, -68, 10, -57, 38, -67, -43, -108, 111, -67, -10, 19, -26, -67, -61, 109, 100, 59, 75, -79, -103, 61, 50, 14, 10, 61, -86, 28, -82, -68, -58, 0, 68, 62, 81, -12, -53, 61, -65, -126, -62, 61, 89, 24, 40, -66, 86, -122, -48, 60, 71, 50, -120, 60, -8, -114, 15, 59, -102, 27, 52, 61, -43, 2, 99, 60, -26, 2, -44, 61, -101, -114, 119, -67, 104, 35, 87, 61, 83, 13, 115, 61, -115, 69, -21, 60, 88, -14, -123, 61, -21, -128, 33, -67, -38, -44, -49, -67, -74, -38, -119, -67, 75, -25, 120, 61, 62, -68, -119, 58, -119, -85, 113, 61, -2, 127, -86, -68, -126, -95, -120, -67, -6, -4, -30, 61, -121, -81, 45, -68, -6, -84, 74, -66, 85, -61, -124, 61, 113, -94, -79, -67, -91, 79, 115, -67, -46, 113, -97, -67, 5, 11, 95, 61, -31, 107, 72, 59, 25, 10, -13, 59, 113, 6, 14, -66, 96, -97, 28, 61, 111, 124, -88, -68, -33, 82, 24, 59, -10, 88, 59, 60, -97, 33, 11, 60, -122, -6, 121, -67, 109, 91, -101, -67, -93, -63, -78, 61, 56, -19, -89, 60, 23, -121, -117, 61, 83, -95, 1, 62, -26, 98, 98, -67, 67, -74, 9, 61, -19, 49, 31, 61, 115, 77, 84, -67, 65, 4, 42, 62, 97, -103, 89, -67, 114, -95, 111, 61, 2, -81, 10, 62, 81, -4, -122, 60, 75, -107, -128, -67, 34, -40, -109, -67, 24, 119, 55, -67, 9, 40, -65, -69, -5, -97, -101, -70, 30, -93, -61, 61, -97, 4, -47, -70, 114, 66, 91, 61, -109, -77, -87, 61, 30, 25, -79, -68, -58, 110, -92, 61, 113, 123, -44, 60, -57, 25, 49, 61, -91, 44, -64, 61, -122, -103, -92, -67, -15, -92, 64, -68, 33, 16, -63, -69, -112, -10, -12, 60, 81, -110, -4, -67, -40, -116, 72, -67, 6, 21, 100, -67, 57, 63, -126, 60, 38, -81, 77, -68, 87, -121, 93, 60, -87, 103, 1, 62, 7, -98, 92, 61, -63, 85, 101, 60, -98, -1, 119, 60, 47, 96, 107, -67, 30, -65, 78, -68, 80, -37, -40, 61, 97, 52, 49, -69, -95, -12, -30, -67, 49, 48, -10, 61, 78, 2, 50, 60, -103, -46, -62, -68, -1, 83, 45, 61, 92, 58, 3, -67, -51, 107, -110, 60, -70, 16, -61, 61, 81, 24, -74, -67, -25, -124, 4, -66, 118, 107, -27, -68, 16, -46, 117, -67, 22, -11, -100, -67, 73, 38, -120, 61, 2, -63, 10, 59, -110, 50, 48, 60, 48, 77, 31, -67, -3, 75, -79, 60, -103, 21, -36, -68, -104, -89, -62, 61, 82, 73, -21, 61, -102, 4, 52, -67, -33, -38, -69, 61, -43, -51, 32, 61, -5, -71, -72, -67, -71, -42, 49, -69, -31, -26, -108, 61, 65, 109, -96, 61, -41, -53, 28, -66, 105, 91, -96, -67, -55, -12, -128, 61, 29, 117, -43, -69, -56, 48, 44, 61, 72, -56, -85, 61, -83, 4, 83, 61, -117, -78, -40, -67, -23, 49, -116, 60, -89, 127, -89, -67, 40, -69, -60, 61, -83, -89, -36, 60, -40, -7, 106, 60, 23, 122, 79, -67, -40, 78, 62, -67, 8, 72, 52, 60, 10, -90, 14, 62, -112, 117, -35, -67, -66, 28, -120, -67, -26, -26, 62, -67, -61, 40, -125, -67, -26, 68, 38, 61, -86, 96, -26, -68, 37, 32, 48, -68, 9, 126, -108, -67, 58, 1, 55, -67, -41, -110, 27, -67, 74, 70, -64, -67, 93, 53, -83, 61, -64, -20, -58, 61, -51, 88, -88, -67, 31, -19, -66, 60, 94, -112, 118, -67, -9, 75, -122, 61, -29, -100, 54, -68, -30, 118, 5, 60, 18, 74, 17, -68, 9, 38, -112, 61, -34, -70, 72, 59, 23, 0, -123, -67, -103, -16, 56, -67, -30, -59, 13, -67, -109, 46, -90, -67, 114, 82, -75, 61, 35, 111, -39, -69, -61, -108, -97, 60, -100, 112, -120, 60, -111, 94, -67, 61, 85, -90, 29, 61, -51, -120, 127, 61, -11, 57, -64, -67, -53, -60, -34, 61, -53, 84, 82, -68, 31, 108, -39, -67, -57, -14, 17, -67, 27, -60, -35, -68, -91, -7, 38, 61, -26, 80, 60, -68, -89, 45, 100, -68, 109, -98, -20, 60, -14, -120, -71, -68, -57, -113, -60, 60, -83, 16, 26, 61, -77, 86, 2, -67, 58, 89, 111, 61, 97, -17, -7, 61, -53, 28, 36, -70, 101, -6, 108, 61, -45, -98, -12, 61, -112, -79, -108, -67, 8, -119, -43, 61, 111, 59, -94, 59, 113, 74, 4, 61, -107, 105, -114, 60, 71, 92, -76, -69, -42, 122, -92, -68, -33, -98, -16, 59, 114, -105, -85, -68, 55, -66, -15, 59};

            Set<String> faceRedisKeys = coolCache.keys(CommonConstant.USER_FACE_ENGINE + arcsoftProperties.getAppName() + ":*");
            log.info("缓存人脸共计数量：{}", faceRedisKeys.size());

            if (faceRedisKeys.size() > 0) {
                //开始执行循环比较
                for (String faceRedisKey : faceRedisKeys) {
                    String featureData = coolCache.get(faceRedisKey).toString();
                    //byte[] sourceFeatureData = Convert.hexToBytes(featureData);
                    // featureData = featureData.replace("[", "").replace("]", "");
                    // byte[] sourceFeatureData = Convert.toPrimitiveByteArray(featureData);

                    byte[] sourceFeatureData = Base64.decode(featureData);
                    FaceFeature sourceFaceFeature = new FaceFeature();
                    sourceFaceFeature.setFeatureData(sourceFeatureData);
                    FaceSimilar faceSimilar = new FaceSimilar();
                    int code = faceEngine.compareFaceFeature(faceFeature, sourceFaceFeature, faceSimilar);
                    Long similarUserId = Convert.toLong(StrUtil.subAfter(faceRedisKey, ":", true));
                    //log.info("缓存比对的人脸分数：{}", faceSimilar.getScore());
                    if (code == 0) {
                        // 获取最大的人脸相似分数
                        if (faceSimilar.getScore() > faceSimilarData.getMaxSimilarScore()) {
                            faceSimilarData.setUserId(similarUserId);
                            faceSimilarData.setMaxSimilarScore(faceSimilar.getScore());
                        }
                        //取分数大于阈值的人脸
                        if (faceSimilar.getScore() >= maxScore) {
                            log.info("缓存比对合规的用户id：{}", similarUserId);
                            log.info("缓存比对合规的人脸分数：{}", faceSimilar.getScore());
                            FaceVO face = new FaceVO();
                            face.setUserId(similarUserId);
                            face.setScore(faceSimilar.getScore());
                            userFaceList.add(face);
                        }
                    }
                }
            }

            if (userFaceList.size() > 0) {
                log.info("缓存比对共计匹配到：{} 人", userFaceList.size());
                //最后取最大的一个判别人脸检测用户
                FaceVO faceVOInfo = userFaceList.stream()
                        .max(Comparator.comparing(item -> item.getScore()))
                        .get();

                log.info("***缓存比对最匹配人脸信息id：{}", faceVOInfo.getUserId());
                log.info("***缓存比对最匹配人脸信息分数：{}", faceVOInfo.getScore());

                userId = faceVOInfo.getUserId();

                if (ObjectUtil.isNotEmpty(faceVOInfo)) {
                    //注册人脸信息
                    AppUserFace appUserFace = mapper.selectOneByQuery(new QueryWrapper().eq("user_id", userId));
                    Integer searchId = 0;
                    if (ObjectUtil.isEmpty(appUserFace)) {
                        //寻找最后一条数据
                        searchId = baseMapper.selectLastSearchId();
                        searchId = ObjectUtil.isEmpty(searchId) ? 1 : searchId + RandomUtil.randomInt(1, 10);
                    } else {
                        searchId = appUserFace.getSearchId();
                    }
                    FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
                    faceFeatureInfo.setSearchId(searchId);
                    faceFeatureInfo.setFaceTag(userId + "用户人脸数据, 对应SearchId为：" + searchId);
                    faceFeatureInfo.setFeatureData(faceFeature.getFeatureData());

                    int registerCode = faceEngine.registerFaceFeature(faceFeatureInfo);
                    if (registerCode != 0) {
                        return R.ok()
                                .put("code", 350)
                                .put("code", 2)
                                .put("message", "系统登记人脸信息失败，请重新操作");
                    }
                }
            } else {
                //return R.error("引擎缓存均未匹配到对应用户信息，请联系管理员重新进行人脸上传");
                return R.ok()
                        .put("code", 450)
                        .put("data", result)
                        .put("message", "未匹配到对应用户信息，请联系管理员重新进行人脸上传");
            }
        }

        //查询配置的用户
        AppUser userInfo = appUserMapper.selectOneById(userId);
        if (ObjectUtil.isEmpty(userInfo)) {
            return R.error("未查询到对应用户信息");
        }
        if (ObjectUtil.isEmpty(userInfo) && userFaceList.size() > 1) {
            coolCache.del(CommonConstant.USER_FACE_ENGINE  + arcsoftProperties.getAppName() + ":"+ userId);
            // 重新调用人脸识别
            compareFeature(faceVO, type);
        } else {
            result.put("userInfo", userInfo);
            return R.ok(result);
        }
        return R.error("未匹配到对应用户信息");
    }

    @Override
    public R deleteFeature(Long userId) {
        // 根据userId查询face信息
        AppUserFace appUserFace = mapper.selectOneByQuery(new QueryWrapper().eq("user_id", userId));
        if (ObjectUtil.isNotEmpty(appUserFace)) {
            // 获取人脸解析引擎
            FaceEngine faceEngine = FaceEngineCenter.getFaceEngine();
            FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();
            int faceFeatureInfoCode = faceEngine.getFaceFeature(appUserFace.getSearchId(), faceFeatureInfo);
            if (faceFeatureInfoCode == 0) {
                faceFeatureInfo.setSearchId(appUserFace.getSearchId());
                String feature = appUserFace.getFeature();
                // String replace = feature.replace("[", "").replace("]", "");
                // byte[] featureBytes = Convert.toPrimitiveByteArray(replace);
                byte[] featureBytes = Base64.decode(feature);
                Arrays.fill(featureBytes, (byte) 0);
                faceFeatureInfo.setFeatureData(featureBytes);
                int updateResult = faceEngine.updateFaceFeature(faceFeatureInfo);
                log.info("移除更新人脸Code：{}", updateResult);
                int removeResult = faceEngine.removeFaceFeature(appUserFace.getSearchId());
                log.info("移除人脸Code：{}", removeResult);
                log.info("移除人脸状态：{}", removeResult == 0 ? "正常" : "异常");
                if (removeResult != 0) {
                    return R.error("删除人脸引擎信息失败");
                }
            }
            // 删除缓存信息
            coolCache.del(CommonConstant.USER_FACE_ENGINE + arcsoftProperties.getAppName() + ":" + userId);
			/*if (!delSign) {
				return R.error("删除人脸缓存信息失败");
			}*/
            // 删除人脸文件
            FileUtil.del(appUserFace.getFaceFilePath());
            // 删除face信息
            baseMapper.deleteById(appUserFace.getId());
        }
        return R.ok("删除人脸信息成功");
    }

    public FaceEngine getFaceEngine() {
        String appName = arcsoftProperties.getAppName();
        if (!faceEngineCenter.isEmpty() && faceEngineCenter.containsKey(appName)) {
            return faceEngineCenter.get(appName);
        }
        FaceEngine faceEngine = initFaceEngine();
        VersionInfo versionInfo = faceEngine.getVersion();
        versionInfo.setVersion(appName + "-" + DateUtil.formatDateTime(new Date()));
        faceEngineCenter.put(appName, faceEngine);
        return faceEngine;
    }

    public FaceEngine initFaceEngine() {
        String directory = arcsoftProperties.getDirectory();
        String authorizationMode = arcsoftProperties.getAuthorizationMode();
        String appId = arcsoftProperties.getAppId();
        String sdkKey = arcsoftProperties.getSdkKey();
        String activeKey = arcsoftProperties.getActiveKey();
        if (ObjectUtil.isEmpty(appId)) {
            throw new IllegalArgumentException("未找到对应人脸APPID的配置，请核实！");
        }
        if (ObjectUtil.isEmpty(sdkKey)) {
            throw new IllegalArgumentException(String.format("未找到对应人脸SDKKEY的配置，请核实！"));
        }
        // 判断环境
        String libPath = directory + "/face/lib";
        String authPath = directory + "/face/auth";
        boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
        if (isWindows) {
            libPath = "D:\\Env\\Arcsoft\\lib";
            authPath = "D:\\Env\\Arcsoft\\auth";
        }

        FaceEngine faceEngine = new FaceEngine(libPath);
        // 激活引擎
        // int errorCode = faceEngine.activeOnline(appIdConfigure.getConVal(), sdkKeyConfigure.getConVal());

        // 判断是在线还是离线激活
        int activeCode = -1;
        if (authorizationMode.equals("online")) {
            activeCode = faceEngine.activeOnline(
                    appId,
                    sdkKey,
                    activeKey
            );
        } else {
            // 判断是否有离线文件
            String devicesInfo = authPath + File.separator + "devicesInfo.txt";
            if (!FileUtil.exist(devicesInfo)) {
                ActiveDeviceInfo activeDeviceInfo = new ActiveDeviceInfo();
                activeCode = faceEngine.getActiveDeviceInfo(activeDeviceInfo);
                log.info("获取设备信息状态码：{}", activeCode);
                log.info("设备信息：{}", activeDeviceInfo.getDeviceInfo());
                // FileUtil.newFile(devicesInfo);
                FileUtil.appendUtf8String(activeDeviceInfo.getDeviceInfo(), devicesInfo);
                throw new CoolException("已成功生成离线激活设备文件，请联系管理员进行离线激活配置");
            } else {
                authPath = authPath + File.separator + "ArcFacePro64.dat";
                if (!FileUtil.exist(authPath)) {
                    throw new CoolException("未检测到离线激活文件，请添加，目录为：" + authPath);
                }
                activeCode = faceEngine.activeOffline(authPath);
            }
        }

        log.info("引擎激活状态码：{}", activeCode);

        if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.info("引擎激活失败");
        }

        ActiveDeviceInfo activeDeviceInfo = new ActiveDeviceInfo();
        // 采集设备信息（可离线）
        activeCode = faceEngine.getActiveDeviceInfo(activeDeviceInfo);
        log.info("采集设备信息状态码Code: {}", activeCode);
        log.info("设备信息: {}", activeDeviceInfo.getDeviceInfo());

        ActiveFileInfo activeFileInfo = new ActiveFileInfo();
        activeCode = faceEngine.getActiveFileInfo(activeFileInfo);
        if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.info("获取激活文件信息失败");
        }

        // 引擎配置
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
        engineConfiguration.setDetectFaceMaxNum(10);
        // engineConfiguration.setDetectFaceScaleVal(16);
        // 功能配置
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        functionConfiguration.setSupportAge(true);
        // functionConfiguration.setSupportFace3dAngle(true);
        functionConfiguration.setSupportFaceDetect(true);
        functionConfiguration.setSupportFaceRecognition(true);
        functionConfiguration.setSupportGender(true);
        functionConfiguration.setSupportLiveness(true);
        functionConfiguration.setSupportIRLiveness(true);
        functionConfiguration.setSupportImageQuality(true);
        functionConfiguration.setSupportMaskDetect(true);
        // functionConfiguration.setSupportUpdateFaceData(true);
        engineConfiguration.setFunctionConfiguration(functionConfiguration);

        // 初始化引擎
        activeCode = faceEngine.init(engineConfiguration);
        if (activeCode != ErrorInfo.MOK.getValue()) {
            log.info("初始化引擎失败");
        }
        VersionInfo version = faceEngine.getVersion();
        log.info("当前人脸检测版本：{}", version);

        return faceEngine;
    }

    public void delFaceFile(String faceFilePath) {
        if (FileUtil.exist(faceFilePath)) {
            FileUtil.del(faceFilePath);
        }
    }
}
